package cn.tedu.d17_thread2;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
 改造售票案例---加锁
 问题1：重买  一张票卖给了多个人
 问题2：超卖  卖出了0 -1 -2
 */
public class TestSaleTicketsV2 {
    public static void main(String[] args) {

        SaleTicketsV2 target=new SaleTicketsV2();

        /*线程池(ExecutorService)：用来存放线程的池子，新建线程/启动线程/销毁线程...
        * Executors:创建线程池对象
        * */
        //Executors.newFixedThreadPool(5);//创建一个5个大小的线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i <5; i++) {
            /*execute()让线程池中的线程执行目标业务,每次调用启动一个线程*/
            pool.execute(target);
        }
        //pool.shutdownNow();

/*     Thread t1=new Thread(target,"一号窗口");
        Thread t2=new Thread(target,"二号窗口");
        Thread t3=new Thread(target,"三号窗口");
        Thread t4=new Thread(target,"四号窗口");

        //启动线程 由新建状态转为就绪状态，等待CPU调用
        t1.start();
        t2.start();
        t3.start();
        t4.start();*/

    }

}
/**
 * 多线程中出现数据不安全的前提：
 * 1.多线程程序(单线程不存在安全问题)
 * 2.有共享数据
 * 3.多条语句操作共享数据
 * 解决方案：
 * 添加同步锁：把容易出现问题的代码锁起来(注意锁的范围！！！)
 */

class SaleTicketsV2 implements Runnable{

    //定义静态票数，要不每次调用都会初始化
    static int tickets=100;

    //创建唯一的锁对象，之后不论哪个线程进入同步代码块，使用的都是这个对象
    Object o=new Object();

    //1.synchronized修饰同步方法
    //2.synchronized代码块包裹
    /*
     如果一个方法中的代码几乎都被synchronized同步了，
     可以直接把该方法修饰成同步方法。

     锁对象必须是同一个锁对象！！！
     */
    @Override
    // 2.synchronized public void run() {
     public void run() {

        while (true) {

            /*
             同步代码块：
             同一时间这个代码块只能被一个线程享有
            */
            synchronized (o) {

                if (tickets > 0) {

                    try {
                        Thread.sleep(10);//休眠10ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //打印当前售票窗口线程名及票数
                    System.out.println(Thread.currentThread()
                            .getName() + "=" + tickets--);
                }

                if (tickets<=0) break;
            }
        }
    }
}
